![]() |
AVR675 Configurable Three Phase Fan
2.0
|
00001 /* This file has been prepared for Doxygen automatic documentation generation.*/ 00055 #include <avr/io.h> 00056 #include <avr/interrupt.h> 00057 #include <avr/eeprom.h> 00058 00059 00060 //***************************************************************************** 00061 // Declarations 00062 //***************************************************************************** 00063 00064 // Driver stage pin mapping. 00065 #define UL PB0 // UL 00066 #define UH PB1 // UH 00067 #define VL PB2 // VL 00068 #define VH PB3 // VL 00069 #define WL PB4 // WL 00070 #define WH PB5 // WH 00071 00072 #define EDGE_FALLING 1 // Zero crossing polarity flag value for falling zero crossing. 00073 #define EDGE_RISING 0 // Zero crossing polarity flag value for rinsing zero crossing. 00074 00075 #define UPPER_DRIVE_MASK ((1 << UH) | (1 << VH) | (1 << WH)) 00076 00077 #define UPPER_DRIVE_STEP1_CW (1 << VH) // Drive pattern for commutation step 1, CW rotation. 00078 #define UPPER_DRIVE_STEP2_CW (1 << UH) // Drive pattern for commutation step 2, CW rotation. 00079 #define UPPER_DRIVE_STEP3_CW (1 << UH) // Drive pattern for commutation step 3, CW rotation. 00080 #define UPPER_DRIVE_STEP4_CW (1 << WH) // Drive pattern for commutation step 4, CW rotation. 00081 #define UPPER_DRIVE_STEP5_CW (1 << WH) // Drive pattern for commutation step 5, CW rotation. 00082 #define UPPER_DRIVE_STEP6_CW (1 << VH) // Drive pattern for commutation step 6, CW rotation. 00083 00084 00085 #define LOWER_DRIVE_STEP1_CW (1 << WL) // Drive pattern for commutation step 1, CW rotation. 00086 #define LOWER_DRIVE_STEP2_CW (1 << WL) // Drive pattern for commutation step 2, CW rotation. 00087 #define LOWER_DRIVE_STEP3_CW (1 << VL) // Drive pattern for commutation step 3, CW rotation. 00088 #define LOWER_DRIVE_STEP4_CW (1 << VL) // Drive pattern for commutation step 4, CW rotation. 00089 #define LOWER_DRIVE_STEP5_CW (1 << UL) // Drive pattern for commutation step 5, CW rotation. 00090 #define LOWER_DRIVE_STEP6_CW (1 << UL) // Drive pattern for commutation step 6, CW rotation. 00091 00092 // Loop Compensation 00093 #define HALF_LIMIT 0x7FFFu 00094 #define LOOP_SCALING 3u 00095 00096 // Input command Pin 00097 #define CMD_PIN PA4 // PWM or UART input command 00098 #define CMD_PIN_TEST (PINA & (1<<CMD_PIN)) // Test command pin 00099 #define CMD_PIN_0 (1<<CMD_PIN) // Test for pin low (inverted circuitry) 00100 #define CMD_PIN_1 0 // Test for pin high (inverted circuitry) 00101 00102 00103 // TACH and Alarm Pin 00104 #define TACH_PIN PA0 //PA0 00105 #define TACH_PIN_0 PORTA |= (1<<TACH_PIN) //inverted for Configurable BLDC Fan Board 00106 #define TACH_PIN_1 PORTA &= ~(1<<TACH_PIN) //inverted for Configurable BLDC Fan Board 00107 00108 // Test Pin 00109 #define TEST_PIN PA3 //PA3 00110 #define TEST_PIN_0 PORTA &= ~(1<<TEST_PIN) 00111 #define TEST_PIN_1 PORTA |= (1<<TEST_PIN) 00112 00113 // LED Pin 00114 #define LED_PIN PB6 //PB6 00115 #define LED_PIN_0 PORTB &= ~(1<<LED_PIN) 00116 #define LED_PIN_1 PORTB |= (1<<LED_PIN) 00117 #define LED_PIN_TOGGLE PORTB ^= (1<<LED_PIN) 00118 00119 // ADC Channels 00120 #define ADC_PRESCALER 4 //divide by 16 (1MHz ADC clock) 00121 00122 #define ADC_MUX_I 0x22 // ADC2+Bit 5 – ADLAR: ADC Left Adjust Result 00123 #define ADC_MUX_W 0x24 // ADC4+Bit 5 – ADLAR: ADC Left Adjust Result 00124 #define ADC_MUX_U 0x25 // ADC6+Bit 5 – ADLAR: ADC Left Adjust Result 00125 #define ADC_MUX_V 0x26 // ADC5+Bit 5 – ADLAR: ADC Left Adjust Result 00126 00127 // Variables 00128 #define VARIABLE_TABLE_SIZE 16 // number of bytes in table 00129 00130 // EEPROM 00131 #define EEPROM_TABLE_SIZE 32 // number of bytes in table 00132 00133 // EEPROM 00134 #define HEADER_SIZE 64 // number bytes (0xFF values) sent between data 00135 00136 00137 //***************************************************************************** 00138 // Tables (RAM) 00139 //***************************************************************************** 00140 00141 uint8_t adc_mux_table_forward[6] = 00142 { 00143 ADC_MUX_V, 00144 ADC_MUX_U, 00145 ADC_MUX_W, 00146 ADC_MUX_V, 00147 ADC_MUX_U, 00148 ADC_MUX_W 00149 }; 00150 00151 00152 // Table of upper output patterns for forward driving. 00153 uint8_t upper_comm_table_forward[6] = 00154 { 00155 UPPER_DRIVE_STEP2_CW, 00156 UPPER_DRIVE_STEP1_CW, 00157 UPPER_DRIVE_STEP6_CW, 00158 UPPER_DRIVE_STEP5_CW, 00159 UPPER_DRIVE_STEP4_CW, 00160 UPPER_DRIVE_STEP3_CW 00161 }; 00162 00163 00164 // Table of lower output patterns for forward driving. 00165 uint8_t lower_comm_table_forward[6] = 00166 { 00167 LOWER_DRIVE_STEP2_CW, 00168 LOWER_DRIVE_STEP1_CW, 00169 LOWER_DRIVE_STEP6_CW, 00170 LOWER_DRIVE_STEP5_CW, 00171 LOWER_DRIVE_STEP4_CW, 00172 LOWER_DRIVE_STEP3_CW 00173 }; 00174 00175 00176 // Edge Level ZC for forward driving. 00177 uint8_t zc_table_forward[6] = 00178 { 00179 EDGE_RISING, 00180 EDGE_FALLING, 00181 EDGE_RISING, 00182 EDGE_FALLING, 00183 EDGE_RISING, 00184 EDGE_FALLING 00185 }; 00186 00187 00188 //***************************************************************************** 00189 // Global Variables 00190 //***************************************************************************** 00191 00192 00193 // Loop Counter 00194 uint8_t pwm_counter = 0; 00195 00196 uint8_t bit_test = 0; 00197 00198 // PWM output 00199 uint16_t pwm_value; 00200 00201 // Commutation and Timer 00202 uint8_t commutation_step = 0; 00203 uint16_t comm_period; 00204 uint16_t comm_period_temp; 00205 uint16_t timer_capture; 00206 uint16_t timer_capture_last; 00207 00208 // PWM input command 00209 uint16_t pwm_cmd; 00210 uint16_t pwm_cmd_next; 00211 uint8_t pwm_cmd_updated; 00212 uint16_t pwm_cmd_filter; 00213 uint16_t pwm_cmd_filtered; 00214 00215 // Motor Commutation 00216 // Commutation interrupt state 0 = update comm state, 1 = back EMF sample 00217 uint8_t comm_inter_state; 00218 00219 // ADC Samples 00220 uint8_t bemf_sampled; 00221 uint8_t adc_sample; 00222 uint8_t get_bemf; 00223 00224 // Back EMF Phase Locked Loop Compensation 00225 uint16_t y0 = 0; // Current Speed Count * 16 00226 uint16_t y1 = 0; // Last Speed Count * 16 00227 uint16_t r0 = 0; // Current Back EMF error voltage 00228 uint16_t nr0 = 0; // Positive Compensation * 128 00229 uint16_t r0_temp = 0; // Current Back EMF error voltage 00230 uint16_t nr0_temp = 0; // Positive Compensation * 128 00231 uint16_t y0_min; // Lower limit 00232 uint16_t y0_max; // Upper limit 00233 00234 //Speed Loop Compensation 00235 uint16_t speed_cmd_calc; // Calculated speed command 00236 uint16_t slope; 00237 uint16_t delta; 00238 uint16_t intercept; 00239 uint16_t s_y0 = 0; // Speed Loop Count 00240 uint16_t s_y1 = 0; // Last Speed Loop Count 00241 uint16_t s_r0 = 0; // Current Speed Loop error voltage 00242 uint16_t s_nr0 = 0; // Current Speed Loop error voltage (negative) 00243 uint16_t s_y0_min; // lower limit 00244 uint16_t s_y0_max; // upper limit 00245 00246 //Communication Data 00247 uint8_t comm_data; 00248 uint8_t data_toggle; 00249 00250 //PWM Timer Back EMF Sampling variables 00251 uint8_t adc_sample_state = 0; // 0 = current, 1 = current, 2 = v_bus, 00252 // 3 = Back EMF 00253 uint8_t bemf_ready = 0; // 0 = not ready, 1 = ready 00254 uint8_t commutation_step_sampled = 0; 00255 uint16_t neutral_averaging; 00256 uint8_t neutral = 0; 00257 00258 // Speed Loop counts 00259 uint8_t s_loop_count = 0; 00260 00261 // Operation mode 00262 uint8_t input_state = 1; // 0 = PWM input, 1 = UART Data In 00263 uint8_t output_state = 1; // 0 = Tach output, 1 = UART Data Out 00264 uint8_t control_state = 1; // 0 = Speed Control, 1 = Open Loop PWM 00265 00266 // LED 00267 uint16_t led_blink_count = 0; 00268 00269 00270 // EEPROM Parameters 00271 uint8_t valid_byte; 00272 uint8_t eeprom_number; 00273 00274 uint8_t motor_kpv; 00275 uint8_t motor_kiv; 00276 uint8_t motor_max_speed; 00277 uint8_t motor_norm_speed; 00278 uint8_t motor_min_speed; 00279 00280 // Serial in 00281 uint8_t bit_count_low; 00282 uint8_t bit_position; 00283 uint16_t bit_timeout; 00284 uint16_t byte_timeout; 00285 uint8_t data_in; 00286 00287 uint8_t motor_off; // bit 0 = motor off command, 00288 // bit 1 = motor turned off, bit 2 = transfer variables back to EEPROM 00289 uint8_t pin_test; //pin test for calibration 00290 00291 uint8_t count_dir; 00292 00293 00294 // Counter for table operations 00295 uint8_t table_counter = 0; 00296 00297 // Variable and EEPROM table 00298 uint8_t variable_table[VARIABLE_TABLE_SIZE + EEPROM_TABLE_SIZE]; 00299 00300 // Aliases for variables 00301 #define command variable_table[0] 00302 00303 #define speed_cmd variable_table[1] 00304 #define speed variable_table[2] 00305 #define speed_error variable_table[3] 00306 00307 #define current_limit variable_table[4] 00308 #define current variable_table[5] 00309 00310 #define pwm_limit variable_table[6] 00311 #define pwm variable_table[7] 00312 00313 #define bemf variable_table[8] 00314 #define bemf_error variable_table[9] 00315 00316 #define v_bus variable_table[10] 00317 #define v_motor variable_table[11] 00318 00319 #define osc_cal variable_table[12] 00320 #define osc_error variable_table[13] 00321 00322 #define data_rxd variable_table[14] 00323 00324 #define counter variable_table[15] 00325 00326 // Aliases for EEPROM values 00327 #define enable_voltage variable_table[0 + VARIABLE_TABLE_SIZE] 00328 #define osc_cal_adj variable_table[1 + VARIABLE_TABLE_SIZE] 00329 #define data_watch variable_table[2 + VARIABLE_TABLE_SIZE] 00330 #define mode variable_table[3 + VARIABLE_TABLE_SIZE] 00331 #define input_cmd variable_table[4 + VARIABLE_TABLE_SIZE] 00332 00333 #define speed_count_min variable_table[5 + VARIABLE_TABLE_SIZE] 00334 #define speed_count_max variable_table[6 + VARIABLE_TABLE_SIZE] 00335 #define r0_limit variable_table[7 + VARIABLE_TABLE_SIZE] 00336 #define kp variable_table[8 + VARIABLE_TABLE_SIZE] 00337 #define ki variable_table[9 + VARIABLE_TABLE_SIZE] 00338 #define pll_gravity variable_table[10 + VARIABLE_TABLE_SIZE] 00339 #define pwm_min variable_table[11 + VARIABLE_TABLE_SIZE] 00340 #define pwm_max variable_table[12 + VARIABLE_TABLE_SIZE] 00341 #define s_loop_rate variable_table[13 + VARIABLE_TABLE_SIZE] 00342 #define s_r0_limit variable_table[14 + VARIABLE_TABLE_SIZE] 00343 #define s_kp variable_table[15 + VARIABLE_TABLE_SIZE] 00344 #define s_ki variable_table[16 + VARIABLE_TABLE_SIZE] 00345 00346 #define speed_cmd_min variable_table[17 + VARIABLE_TABLE_SIZE] 00347 #define speed_cmd_max variable_table[18 + VARIABLE_TABLE_SIZE] 00348 #define speed_scale variable_table[19 + VARIABLE_TABLE_SIZE] 00349 00350 #define current_limit_startup variable_table[20 + VARIABLE_TABLE_SIZE] 00351 #define current_limit_max variable_table[21 + VARIABLE_TABLE_SIZE] 00352 #define current_limit_slope variable_table[22 + VARIABLE_TABLE_SIZE] 00353 00354 #define v_bus_min variable_table[23 + VARIABLE_TABLE_SIZE] 00355 00356 #define command_0 variable_table[24 + VARIABLE_TABLE_SIZE] 00357 #define speed_cmd_0 variable_table[25 + VARIABLE_TABLE_SIZE] 00358 #define command_1 variable_table[26 + VARIABLE_TABLE_SIZE] 00359 #define speed_cmd_1 variable_table[27 + VARIABLE_TABLE_SIZE] 00360 #define command_2 variable_table[28 + VARIABLE_TABLE_SIZE] 00361 #define speed_cmd_2 variable_table[29 + VARIABLE_TABLE_SIZE] 00362 #define command_3 variable_table[30 + VARIABLE_TABLE_SIZE] 00363 #define speed_cmd_3 variable_table[31 + VARIABLE_TABLE_SIZE] 00364 00365 00366 //***************************************************************************** 00367 // initialize TACH/Alarm PA0 as output low 00368 //***************************************************************************** 00369 00378 void intTACH(void) 00379 { 00380 PORTA &= ~(1<<TACH_PIN); // set PA0 low 00381 DDRA |= (1<<TACH_PIN); // make PA0 an output 00382 } 00383 00384 00385 //***************************************************************************** 00386 // initialize Test pin 00387 //***************************************************************************** 00388 00400 void intTestPin(void) 00401 { 00402 PORTA &= ~(1<<TEST_PIN); 00403 DDRA |= (1<<TEST_PIN); 00404 } 00405 00406 00407 //***************************************************************************** 00408 // initialize LED pin 00409 //***************************************************************************** 00410 00420 void intLEDPin(void) 00421 { 00422 PORTB &= ~(1<<LED_PIN); 00423 DDRB |= (1<<LED_PIN); 00424 } 00425 00426 00427 //***************************************************************************** 00428 // initialize Timer 0 as Normal, 16-bit mode 00429 //***************************************************************************** 00430 00445 void intTimer0(void) 00446 { 00447 // Set up Timer/counter0 00448 TCCR0A = (1<<TCW0); // Normal, 16-bit mode 00449 TCCR0B = (1<<CS01); // Clk/8 Prescaler for 2MHz timer clock 00450 } 00451 00452 00453 //***************************************************************************** 00454 // initialize PWM on Timer1 00455 //***************************************************************************** 00456 00466 void intPWM(void) 00467 { 00468 //Clear on up-counting. 00469 TCCR1A = (1 << COM1A1) | (0 << COM1A0) | (1 << PWM1A); 00470 00471 //Set WGM to PWM6, dual slope mode. 00472 TCCR1D = (1 << WGM11) | (1 << WGM10); 00473 00474 // 16MHz/2/19200 = 417 counts, 0 to 416 (pwm + pwm>>1 + pwm>>3 + + pwm>>6) 00475 // (255+127+31+3) 00476 TC1H = 1; // 00477 OCR1C = 0xA0; //416 TOPVALUE (pwm + pwm>>1 + pwm>>3 + + pwm>>6) 00478 // (255+127+31+3) 00479 00480 TCCR1B = (1 << CS10); //Prescaler 16MHz clock /1 = 16MHz 00481 00482 //Set PWM pins as output. 00483 // (PWM output is still controlled through TCCR1E register.) 00484 DDRB = (1 << UL)|(1 << UH)|(1 << VL)|(1 << VH)|(1 << WL)|(1 << WH); 00485 } 00486 00487 00488 //***************************************************************************** 00489 // initialize ADC PA1(ADC1),PA5(ADC4),PA6(ADC5),PA7(ADC6) 00490 //***************************************************************************** 00491 00501 void intADC(void) 00502 { 00503 //PA1(ADC1)-DIR,PA5(ADC4)-THR,PA6(ADC5)-IB,PA7(ADC6)-IA, 00504 //PB6(ADC9)-V+,PB7(ADC10)-TEMP 00505 00506 //ADMUX – ADC Multiplexer Selection Register 00507 //Bits 7:6 – REFS1:REFS0: Voltage Reference Selection Bits 00= Vcc 00508 //Bit 5 – ADLAR: ADC Left Adjust Result 00509 //Bits 4:0 – MUX4:0: Analog Channel and Gain Selection Bits 00510 ADMUX = ADC_MUX_I; 00511 00512 //ADCSRA – ADC Control and Status Register A 00513 //Bit 7 – ADEN: ADC Enable 00514 //Bit 6 – ADSC: ADC Start Conversion 00515 //Bit 5 – ADATE: ADC Auto Trigger Enable 00516 //Bits 2:0 – ADPS2:0: ADC Prescaler Select Bits 00517 ADCSRA = ((1<<ADEN) | (1<<ADATE) | ADC_PRESCALER); 00518 00519 //ADCL an ADCH – The ADC Data Register 00520 //read just ADCH for 8 bit values 00521 00522 //ADCSRB – ADC Control and Status Register B 00523 //Timer/Counter1 Overflow - ADTS2 = 1, ADTS1 = 1, ADTS0 = 0 00524 ADCSRB = ((1<<ADTS2) | (1<<ADTS1)); 00525 00526 //DIDR0 – Digital Input Disable Register 0 00527 //Bits 7:4,2:0 – ADC6D:ADC0D: ADC6:0 Digital Input Disable 00528 //Bit 3 – AREFD: AREF Digital Input Disable 00529 DIDR0 |= ((1<<ADC2D)|(1<<ADC4D)|(1<<ADC5D)|(1<<ADC6D)); 00530 00531 // ADATE in ADCSRA - Auto Triggering is enabled by setting 00532 // the ADC Auto Trigger Enable bit 00533 00534 // ADTS in ADCSRB - The trigger source is selected by setting 00535 // the ADC Trigger Select bits 00536 } 00537 00538 00539 00540 //***************************************************************************** 00541 // Read in EEPROM values 00542 //***************************************************************************** 00543 00553 void read_eeprom(void) 00554 { 00555 table_counter = 0; 00556 while (table_counter < EEPROM_TABLE_SIZE) 00557 { 00558 00559 variable_table[VARIABLE_TABLE_SIZE + table_counter]= 00560 eeprom_read_byte((uint8_t*)(table_counter)); 00561 table_counter++; 00562 } 00563 table_counter = 0; 00564 } 00565 00566 00567 //***************************************************************************** 00568 // write EEPROM values 00569 //***************************************************************************** 00570 00580 void write_eeprom(void) 00581 { 00582 cli(); 00583 table_counter = 0; 00584 while (table_counter < EEPROM_TABLE_SIZE) 00585 { 00586 eeprom_write_byte ((uint8_t*)(table_counter), 00587 variable_table[VARIABLE_TABLE_SIZE + table_counter]); 00588 table_counter++; 00589 } 00590 table_counter = 0; 00591 // update_limits(); 00592 motor_off = 0; 00593 sei(); 00594 } 00595 00596 00597 //***************************************************************************** 00598 // test oscillator calibration 00599 //***************************************************************************** 00600 00608 void test_oscillator(void) 00609 { 00610 cli(); 00611 //PC sends stream of 0 bytes at 19200 baud, for a 468.75us period 00612 00613 OCR0B = 0xFF; 00614 OCR0A = 0xFF; 00615 00616 //Capture timer period 00617 pin_test = CMD_PIN_TEST; 00618 while (pin_test == CMD_PIN_1) //wait while pin is high 00619 { 00620 pin_test = CMD_PIN_TEST; 00621 } 00622 00623 // TEST_PIN_0; 00624 00625 pin_test = CMD_PIN_TEST; 00626 while (pin_test == CMD_PIN_0) //wait while pin is low 00627 { 00628 pin_test = CMD_PIN_TEST; 00629 } 00630 00631 TEST_PIN_1; 00632 00633 pin_test = CMD_PIN_TEST; 00634 while (pin_test == CMD_PIN_1) //wait while pin is high 00635 { 00636 pin_test = CMD_PIN_TEST; 00637 } 00638 00639 //Capture timer value 00640 TCNT0H = 0; 00641 TCNT0L = 0; 00642 00643 // TEST_PIN_0; 00644 00645 pin_test = CMD_PIN_TEST; 00646 while (pin_test == CMD_PIN_0) //wait while pin is low 00647 { 00648 pin_test = CMD_PIN_TEST; 00649 } 00650 //Capture timer value again 00651 comm_period = TCNT0L; 00652 comm_period += (TCNT0H<<8); 00653 00654 // TEST_PIN_1; 00655 //At 2us per count period and a period of 468.75us the count should be 234. 00656 osc_error = comm_period + 128 - 833; 00657 motor_off = 0; 00658 00659 // TEST_PIN_0; 00660 00661 sei(); 00662 } 00663 00664 00665 //***************************************************************************** 00666 // Enable Interrupts 00667 //***************************************************************************** 00668 00676 void intInterrupts(void) 00677 { 00678 cli(); 00679 //TIMSK – Timer/Counter1 Interrupt Mask Register 00680 //Bit 4 – OCIE0A: Timer/Counter0 Output Compare Match A Interrupt Enable 00681 TIMSK |= (1<<OCIE0A); 00682 //Bit 2 – TOIE1: Timer/Counter1 Overflow Interrupt Enable 00683 TIMSK |= (1<<TOIE1); 00684 //Bit 3 – ADIE: ADC Interrupt Enable 00685 ADCSRA |= (1<<ADIE); //Bit 3 – ADIE: ADC Interrupt Enable 00686 sei(); 00687 } 00688 00689 00690 //***************************************************************************** 00691 // ADC Interrupt - Triggered off of TOV1 00692 //***************************************************************************** 00693 00704 ISR(ADC_vect) 00705 { 00706 TEST_PIN_1; 00707 if(adc_sample_state == 0 ) 00708 { 00709 current = ADCH; 00710 ADMUX = adc_mux_table_forward[commutation_step]; 00711 commutation_step_sampled = commutation_step; 00712 adc_sample_state = 1; 00713 00714 } 00715 else 00716 { 00717 bemf_sampled = ADCH; 00718 00719 if (get_bemf) 00720 { 00721 00722 if (commutation_step_sampled == commutation_step) 00723 { 00724 bemf = bemf_sampled; 00725 neutral_averaging = (neutral_averaging - neutral) + bemf; 00726 v_bus = neutral_averaging>>5; 00727 neutral = v_bus>>1; 00728 if (pwm < 20) 00729 { 00730 // Below 20 counts sample window is too small 00731 v_bus = neutral; 00732 } 00733 00734 bemf_ready = 1; 00735 // Increasing Back EMF 00736 if (zc_table_forward[commutation_step_sampled] == 0) 00737 { 00738 if (bemf <= neutral) // Too Fast 00739 { 00740 r0_temp = 0; 00741 nr0_temp = neutral - bemf; 00742 } 00743 else // Too Slow 00744 { 00745 r0_temp = bemf - neutral; 00746 nr0_temp = 0; 00747 } 00748 } 00749 else 00750 { 00751 if (bemf <= neutral) // Too Slow 00752 { 00753 r0_temp = neutral - bemf; 00754 nr0_temp = 0; 00755 } 00756 else // Too Fast 00757 { 00758 r0_temp = 0; 00759 nr0_temp = bemf - neutral; 00760 } 00761 } 00762 } 00763 get_bemf = 0; 00764 } 00765 00766 ADMUX = ADC_MUX_I; 00767 adc_sample_state = 0; 00768 } 00769 00770 TEST_PIN_0; 00771 } 00772 00773 00774 //***************************************************************************** 00775 // Timer1 PWM Interrupt - Center of PWM period 00776 //***************************************************************************** 00777 00790 ISR(TIMER1_OVF_vect) 00791 { 00792 TEST_PIN_1; 00793 if (CMD_PIN_TEST == CMD_PIN_1) 00794 { 00795 pwm_cmd_next++; 00796 if (bit_position > 0) 00797 { 00798 byte_timeout=0; 00799 bit_timeout++; 00800 if (bit_timeout > 1920) //100ms 00801 { 00802 bit_position = 0; 00803 } 00804 } 00805 else 00806 { 00807 bit_timeout = 0; 00808 } 00809 00810 byte_timeout++; 00811 if((bit_count_low > 6)&&(bit_count_low < 10)) // 7, 8, or 9 PWM periods 00812 { 00813 data_in = 0; 00814 bit_position++; 00815 bit_timeout = 0; 00816 } 00817 if((bit_count_low > 2)&&(bit_count_low < 6)) // 3, 4, or 5 PWM periods 00818 { 00819 data_in = 1; 00820 bit_position++; 00821 bit_timeout = 0; 00822 } 00823 bit_count_low = 0; 00824 } 00825 else 00826 { 00827 bit_count_low++; 00828 if (bit_count_low > 9) 00829 { 00830 bit_count_low = 10; 00831 bit_position = 0; 00832 } 00833 } 00834 if (pwm_counter == 0) 00835 { 00836 pwm_cmd = pwm_cmd_next; 00837 pwm_cmd_next = 0; 00838 pwm_cmd_updated = 1; 00839 } 00840 pwm_counter++; 00841 00842 00843 if (input_state == 1) 00844 { 00845 //Serial Data in (sort of) looking for 4 PWMs low = 1 and 00846 // 8 PWMs low = 0 only when UART receive enabled 00847 00848 if (bit_position == 1) 00849 { 00850 data_rxd = 0; //valid start bit 00851 } 00852 if ((bit_position > 0)&&(bit_position < 9)) 00853 { 00854 data_rxd |= data_in<<(bit_position-1); 00855 } 00856 if (bit_position == 8) 00857 { 00858 valid_byte++; 00859 bit_position = 0; //start over 00860 } 00861 00862 if ( byte_timeout >= 19200) //29200/19200Hz = 1sec 00863 { 00864 valid_byte=0; 00865 byte_timeout=0; 00866 } 00867 00868 if (valid_byte == 3) 00869 { 00870 if (eeprom_number < EEPROM_TABLE_SIZE) 00871 { 00872 variable_table[eeprom_number + VARIABLE_TABLE_SIZE] = data_rxd; 00873 } 00874 00875 valid_byte=0; 00876 if ((eeprom_number == 254)&(data_rxd == 254)) 00877 { 00878 motor_off = 5;//Motor off command and variables ready for write 00879 } 00880 if ((eeprom_number == 255)&(data_rxd == 255)) 00881 { 00882 motor_off = 9; // Motor off command and calibrate oscillator 00883 } 00884 } 00885 00886 if (valid_byte == 1) 00887 { 00888 eeprom_number = data_rxd; 00889 valid_byte++; 00890 } 00891 } 00892 else 00893 { 00894 valid_byte=0; 00895 byte_timeout=0; 00896 } 00897 00898 // Software UART Transmit here 00899 if (output_state == 1) 00900 { 00901 if ((pwm_counter & 0x0F) == 0) 00902 { 00903 TACH_PIN_0; //Start Bit 00904 } 00905 else 00906 { 00907 if ((pwm_counter & 0x0F) < 9) 00908 { 00909 if (comm_data & 0x01) //LSB first 00910 { 00911 TACH_PIN_1; // TXD = 1 00912 } 00913 else 00914 { 00915 TACH_PIN_0; // TXD = 0 00916 } 00917 00918 comm_data = comm_data>>1; 00919 } 00920 else 00921 { 00922 TACH_PIN_1; 00923 } 00924 } 00925 } 00926 TEST_PIN_0; 00927 } 00928 00929 00930 //***************************************************************************** 00931 // Interrupt Timer0 00932 //***************************************************************************** 00933 00950 ISR(TIMER0_COMPA_vect) 00951 { 00952 TEST_PIN_1; 00953 if (comm_inter_state == 1) // back EMF sampling 00954 { 00955 get_bemf = 1; 00956 comm_inter_state = 0; // Update Commutation on next interrupt 00957 } 00958 00959 else // update commutation state 00960 { 00961 commutation_step++; 00962 if (commutation_step>=6) 00963 { 00964 commutation_step=0; 00965 } 00966 // Update commutation state 00967 TCCR1E = lower_comm_table_forward[commutation_step]; 00968 PORTB &= ~(UPPER_DRIVE_MASK); 00969 PORTB |= upper_comm_table_forward[commutation_step]; 00970 00971 if (output_state == 0) //Only update on proper commutation state edge 00972 { 00973 if (commutation_step == 0) 00974 { 00975 TACH_PIN_0; 00976 } 00977 if (commutation_step == 3) 00978 { 00979 TACH_PIN_1; 00980 } 00981 } 00982 comm_inter_state = 1; // Back EMF sample on next interrupt 00983 } 00984 00985 // Update Timer Compare Value 00986 timer_capture = timer_capture_last + comm_period; 00987 OCR0B = (timer_capture >> 8); 00988 OCR0A = timer_capture; 00989 timer_capture_last = timer_capture; 00990 00991 TEST_PIN_0; 00992 00993 } 00994 00995 00996 //***************************************************************************** 00997 // Main 00998 //***************************************************************************** 00999 01018 int main(void) 01019 { 01020 intPWM(); // Initialize timer1 as PWM6 mode center aligned 01021 intTimer0(); // Initialize timer0 for commutation timing 01022 intTACH(); // Initialize I/O pin as tachometer out 01023 intTestPin(); // Initialize I/O pin as test pin 01024 intLEDPin(); // Initialize I/O pin as LED indicator 01025 intADC(); // Initialize ADC 01026 read_eeprom(); // Read the EEPROM contents once on power up 01027 intInterrupts(); // Enable interrupts 01028 01029 osc_cal = OSCCAL; // Read the factory calibration once on power up 01030 01031 while(1) 01032 { 01033 01034 led_blink_count++; 01035 if (led_blink_count >= comm_period_temp) 01036 { 01037 LED_PIN_TOGGLE; 01038 led_blink_count = 0; 01039 } 01040 01041 //Recalculated limits in case they have changed from 01042 // Fan Configuration Utility 01043 y0_min = ((speed_count_min<<LOOP_SCALING) + HALF_LIMIT); 01044 y0_max = ((speed_count_max<<LOOP_SCALING) + HALF_LIMIT); 01045 s_y0_min = ((pwm_min<<LOOP_SCALING) + HALF_LIMIT); 01046 s_y0_max = ((pwm_max<<LOOP_SCALING) + HALF_LIMIT); 01047 01048 // Compare DC input voltage (V_bus) with enable_voltage, 01049 // below threshold use defaults 01050 if (v_bus <= enable_voltage) 01051 { 01052 input_state = 1; //0 = pwm input, 1 = UART Data In 01053 output_state = 1; //0 = Tach output, 1 = UART Data Out 01054 control_state = 1; //0 = Speed Control, 1 = Open Loop PWM 01055 OSCCAL = osc_cal; 01056 } 01057 else 01058 { 01059 input_state = (mode & 0x01); //0 = PWM input, 01060 // 1 = UART Data In 01061 output_state = (mode & 0x02)>>1; //0 = Tach output, 01062 // 1 = UART Data Out 01063 control_state = (mode & 0x04)>>2; //0 = Speed Control, 01064 // 1 = Open Loop PWM 01065 if (osc_cal_adj < 33) 01066 { 01067 OSCCAL = osc_cal + osc_cal_adj - 16; 01068 } 01069 else 01070 { 01071 OSCCAL = osc_cal; 01072 } 01073 } 01074 01075 // Wait here for 16 PWM periods to pass - 01076 // Timing for control loop 19200Hz/16 = 1200Hz (833us) 01077 cli(); 01078 bit_test = (pwm_counter & 0x0F); 01079 sei(); 01080 while(bit_test != 0x0F) 01081 { 01082 cli(); 01083 bit_test = (pwm_counter & 0x0F); 01084 sei(); 01085 } 01086 cli(); 01087 bit_test = (pwm_counter & 0x0F); 01088 sei(); 01089 while(bit_test > 0) 01090 { 01091 cli(); 01092 bit_test = (pwm_counter & 0x0F); 01093 sei(); 01094 } 01095 01096 // Calculate Motor Voltage 01097 v_motor = (v_bus*pwm)>>8; 01098 01099 // Write EEPROM function here. Non-reentrant so must disable interrupts 01100 if (motor_off == 7) // bit 0 = motor off command, 01101 // bit 1 = motor turned off, bit 2 = transfer variables back to EEPROM, 01102 // bit 3 = Cal Oscillator 01103 { 01104 write_eeprom(); 01105 } 01106 if (motor_off == 11) // bit 0 = motor off command, 01107 // bit 1 = motor turned off, 01108 // bit 2 = transfer variables back to EEPROM bit 3 = Cal Oscillator 01109 { 01110 test_oscillator(); 01111 } 01112 01113 // Serial Data Selection 01114 if (data_toggle) 01115 { 01116 if (table_counter < (VARIABLE_TABLE_SIZE + EEPROM_TABLE_SIZE)) 01117 { 01118 comm_data = variable_table[table_counter]; 01119 } 01120 else 01121 { 01122 if (table_counter == (VARIABLE_TABLE_SIZE + EEPROM_TABLE_SIZE)) 01123 { 01124 comm_data = 0; // 0 at end of data 01125 } 01126 else 01127 { 01128 comm_data = 255; // The rest of the data is 255s 01129 } 01130 01131 } 01132 table_counter++; 01133 if (table_counter > (HEADER_SIZE + VARIABLE_TABLE_SIZE + 01134 EEPROM_TABLE_SIZE + 1)) 01135 { 01136 table_counter = 0; 01137 comm_data = 0; // 0 at beginning of data 01138 01139 } 01140 data_toggle = 0; 01141 } 01142 else 01143 { 01144 01145 if (count_dir == 0) 01146 { 01147 counter++; 01148 if (counter>254) 01149 { 01150 count_dir = 1; 01151 } 01152 } 01153 else 01154 { 01155 counter--; 01156 if (counter<1) 01157 { 01158 count_dir = 0; 01159 } 01160 } 01161 01162 comm_data = variable_table[data_watch]; 01163 if (comm_data > 254) 01164 { 01165 comm_data = 254; // Clip data at 254 01166 } 01167 data_toggle = 1; 01168 } 01169 01170 01171 // PWM input (Speed command) averaging filter 01172 if (pwm_cmd_updated == 1) 01173 { 01174 pwm_cmd_updated = 0; 01175 pwm_cmd_filter = (pwm_cmd_filter - pwm_cmd_filtered) + pwm_cmd; 01176 pwm_cmd_filtered = pwm_cmd_filter>>6; 01177 if (pwm_cmd_filtered > 255) 01178 { 01179 pwm_cmd_filtered = 255; 01180 } 01181 } 01182 01183 01184 // Check to see where command comes from either 01185 // Fan Configuration Utility of PWM input (Speed command) 01186 if (input_state == 1) 01187 { 01188 command = input_cmd; 01189 } 01190 else 01191 { 01192 command = pwm_cmd_filtered; 01193 } 01194 01195 01196 // Back EMF Sensing PLL Update 01197 if (bemf_ready == 1) 01198 { 01199 01200 cli(); 01201 bemf_ready = 0; 01202 r0=r0_temp; 01203 nr0=nr0_temp; 01204 sei(); 01205 01206 // Back EMF sensing PLL PI regulator 01207 if(r0>r0_limit) 01208 { 01209 r0=r0_limit; 01210 } 01211 if(nr0>r0_limit) 01212 { 01213 nr0=r0_limit; 01214 } 01215 01216 nr0 += pll_gravity; 01217 01218 bemf_error = 128 + r0 - nr0; 01219 01220 y1 += ((r0*ki)>>8); // ki 01221 y1 -= ((nr0*ki)>>8); // ki 01222 01223 if (y1 < y0_min) 01224 { 01225 y1 = y0_min; 01226 } 01227 if (y1 > y0_max) 01228 { 01229 y1 = y0_min; // Restart PLL 01230 } 01231 01232 y0 = y1 + ((r0*kp)>>8) - ((nr0*kp)>>8); // kp 01233 01234 if (y0 < y0_min) 01235 { 01236 y0 = y0_min; 01237 } 01238 if (y0 > y0_max) 01239 { 01240 y0 = y0_min; // Restart PLL 01241 } 01242 01243 if (speed_cmd < speed_cmd_min) 01244 { 01245 y1 = y0_min; // Restart PLL 01246 } 01247 01248 speed = (y0 - HALF_LIMIT) >> LOOP_SCALING; 01249 01250 comm_period_temp = (0xFFFF/speed)>>speed_scale; 01251 01252 cli(); 01253 comm_period = comm_period_temp; 01254 sei(); 01255 } 01256 01257 01258 // Speed Control Loop Update 01259 s_loop_count++; 01260 if (s_loop_count >= s_loop_rate) 01261 { 01262 s_loop_count = 0; 01263 // Speed command Mapping 01264 01265 if (command > command_3) 01266 { 01267 slope = 255 - speed_cmd_3; 01268 delta = command - command_3; 01269 intercept = speed_cmd_3; 01270 } 01271 else 01272 { 01273 if (command > command_2) 01274 { 01275 slope = speed_cmd_3 - speed_cmd_2; 01276 delta = command - command_2; 01277 intercept = speed_cmd_2; 01278 } 01279 else 01280 { 01281 if (command > command_1) 01282 { 01283 slope = speed_cmd_2 - speed_cmd_1; 01284 delta = command - command_1; 01285 intercept = speed_cmd_1; 01286 } 01287 else 01288 { 01289 if (command > command_0) 01290 { 01291 slope = speed_cmd_1 - speed_cmd_0; 01292 delta = command - command_0; 01293 intercept = speed_cmd_0; 01294 } 01295 else 01296 { 01297 slope = 0; 01298 delta = 0; 01299 intercept = 0; 01300 } 01301 } 01302 } 01303 } 01304 01305 speed_cmd_calc = ((slope*delta)/255) + intercept; 01306 01307 // speed_cmd = command; //Linear Mapping for testing purposes 01308 01309 if (speed_cmd_calc > speed_cmd_max) 01310 { 01311 speed_cmd_calc = speed_cmd_max; 01312 } 01313 01314 if (speed_cmd_calc < speed_cmd_min) 01315 { 01316 speed_cmd_calc = speed_cmd_min; 01317 } 01318 01319 speed_cmd = speed_cmd_calc; 01320 01321 // Speed Control PI regulator 01322 if (speed > speed_cmd) 01323 { 01324 s_nr0 = speed - speed_cmd; 01325 s_r0 = 0; 01326 } 01327 else 01328 { 01329 s_r0 = speed_cmd - speed; 01330 s_nr0 = 0; 01331 } 01332 01333 if(s_nr0>s_r0_limit) 01334 { 01335 s_nr0=s_r0_limit; 01336 } 01337 if(s_r0>s_r0_limit) 01338 { 01339 s_r0=s_r0_limit; 01340 } 01341 01342 01343 speed_error = 128 - s_r0 - s_nr0; 01344 01345 s_y1 += ((s_r0*s_ki)>>6); //s_ki 01346 s_y1 -= ((s_nr0*s_ki)>>6); //s_ki 01347 01348 if (s_y1 < s_y0_min) 01349 { 01350 s_y1 = s_y0_min; 01351 } 01352 if (s_y1 > s_y0_max) 01353 { 01354 s_y1 = s_y0_max; 01355 } 01356 01357 s_y0 = s_y1 + ((s_r0*s_kp)>>6) - ((s_nr0*s_kp)>>6); //s_kp 01358 01359 if (s_y0 < s_y0_min) 01360 { 01361 s_y0 = s_y0_min; 01362 } 01363 if (s_y0 > s_y0_max) 01364 { 01365 s_y0 = s_y0_max; 01366 } 01367 01368 pwm = (s_y0 - HALF_LIMIT) >> LOOP_SCALING; 01369 } 01370 01371 // Open Loop PWM or Speed Control 01372 if (control_state == 1) // Direct PWM command for testing purposes 01373 { 01374 01375 if (command>pwm_max) 01376 { 01377 pwm = pwm_max; 01378 } 01379 else 01380 { 01381 pwm = command; 01382 if (pwm < pwm_min) 01383 { 01384 pwm = pwm_min; 01385 } 01386 } 01387 } 01388 01389 // Current limiting 01390 if (speed < speed_cmd_min ) 01391 { 01392 // Lower Current limit gives better startup performance 01393 current_limit = current_limit_startup; 01394 } 01395 else //Higher current limit for high speed operation 01396 { 01397 current_limit = current_limit_startup + 01398 ((((speed - speed_cmd_min)*current_limit_slope)>>8)); 01399 if (current_limit > current_limit_max) 01400 { 01401 // upper current limit for high power operation 01402 current_limit = current_limit_max; 01403 } 01404 } 01405 01406 // Folds back PWM when exceeding current limit 01407 if (current > current_limit) 01408 { 01409 // TEST_PIN_1; 01410 if (pwm_limit > 1) 01411 { 01412 pwm_limit--; 01413 } 01414 } 01415 else 01416 { 01417 if (pwm_limit < pwm) 01418 { 01419 pwm_limit++; 01420 } 01421 } 01422 01423 if (pwm > pwm_limit) 01424 { 01425 pwm = pwm_limit; 01426 } 01427 01428 // Minimum DC Bus Voltage before enabling 01429 // back EMF sensing and speed control 01430 if (v_bus < v_bus_min) 01431 { 01432 pwm = pwm_min; 01433 s_y1 = s_y0_min; // Reset Integrator 01434 s_y0 = 0; // PWM off 01435 y1 = y0_min; // Restart PLL 01436 } 01437 01438 // Motor Off function for updating EEPROM 01439 if (motor_off == 0) 01440 { 01441 // 16MHz/2/19200 = 417 counts, 0 to 416 01442 // (pwm + pwm>>1 + pwm>>3 + + pwm>>6) (255+127+31+3) 01443 pwm_value = pwm + (pwm>>1) + (pwm>>3) + (pwm>>6); 01444 cli(); 01445 TC1H = (pwm_value >> 8); 01446 OCR1A = pwm_value; 01447 sei(); 01448 } 01449 else 01450 { 01451 cli(); 01452 TC1H = 0; 01453 OCR1A = 0; 01454 motor_off |= 2; // Motor PWM at zero 01455 sei(); 01456 //pwm = pwm_min; 01457 s_y1 = s_y0_min; // Reset Integrator 01458 s_y0 = 0; // PWM off 01459 y1 = y0_min; // Restart PLL 01460 } 01461 01462 } 01463 }